import mapboxgl, { type Anchor, type PointLike } from 'mapbox-gl';
import React, {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
import { createPortal } from 'react-dom';
import type Mapless from '../../Mapless';
import ErrorBoundary from '../ErrorBoundary';
import styles from './index.module.less';

// 定义 MapboxMarker 组件的 props 类型
type MapboxMarkerProps = {
  maplessRef?: React.RefObject<Mapless | undefined>;
  lngLat: mapboxgl.LngLatLike;
  children: React.ReactNode;
  className?: string;
  offset?: PointLike;
  offsetX?: number;
  offsetY?: number;
  anchor?: Anchor;
  transparent?: boolean;
};

export interface MapboxMarkerRef {
  show: () => void;
  showOnce: () => void;
  hide: () => void;
}

const MapboxMarker = forwardRef(
  (
    {
      maplessRef,
      lngLat,
      children,
      className,
      offset,
      offsetX,
      offsetY,
      anchor,
      transparent = false,
    }: MapboxMarkerProps,
    ref,
  ) => {
    const markerRef = useRef<mapboxgl.Marker>(undefined);
    const markerNodeRef = useRef(document.createElement('div'));

    const [show, setShow] = useState(false);

    const oncedRef = useRef<boolean>(false);

    useImperativeHandle(
      ref,
      () => ({
        show: () => setShow(true),
        showOnce: () => {
          if (!oncedRef.current) {
            oncedRef.current = true;
            setShow(true);
          }
        },
        hide: () => setShow(false),
      }),
      [],
    );

    useEffect(() => {
      const { map } = maplessRef?.current || {};
      if (!map) return;

      const shouldCreateMarker = show && !markerRef.current;
      const shouldRemoveMarker = !show && markerRef.current;

      if (shouldCreateMarker) {
        const offsetXY = offset || [offsetX || 0, offsetY || 0];
        markerRef.current = new mapboxgl.Marker({
          element: markerNodeRef.current,
          className: `${styles['react-marker']} ${className} ${transparent ? styles.transparent : ''}`,
          offset: offsetXY,
          anchor: anchor || 'center',
        });
        markerRef.current.setLngLat(lngLat);
        markerRef.current.addTo(map);
      } else if (shouldRemoveMarker) {
        markerRef.current?.remove();
        markerRef.current = undefined;
      }

      return () => {
        if (markerRef.current) {
          markerRef.current.remove();
          markerRef.current = undefined;
        }
      };
    }, [show, maplessRef?.current?.map]);

    useEffect(() => {
      if (markerRef.current && lngLat) {
        try {
          const [prevLng, prevLat] = markerRef.current.getLngLat().toArray();
          const [newLng, newLat] = Array.isArray(lngLat)
            ? lngLat
            : (lngLat as mapboxgl.LngLat).toArray();

          if (prevLng !== newLng || prevLat !== newLat) {
            markerRef.current.setLngLat([newLng, newLat]);
          }
        } catch (_e) {
          // Fallback if getLngLat fails
          markerRef.current.setLngLat(lngLat);
        }
      }
    }, [lngLat]);

    useEffect(() => {
      const offsetXY = offset || [offsetX || 0, offsetY || 0];
      markerRef.current?.setOffset(offsetXY);
    }, [offset, offsetX, offsetY]);

    return (
      <ErrorBoundary message="MapboxMarker">
        {createPortal(children, markerNodeRef.current)}
      </ErrorBoundary>
    );
  },
);

export default React.memo(MapboxMarker);
